//-----------------------------------------------------------------------------
//
//  Copyright 2013, STMicroelectronics - All Rights Reserved
//
//  ST makes no warranty express or implied including but not limited to,
//  any warranty of (i) merchantability or fitness for a particular purpose
//  and/or (ii) requirements, for a particular purpose in relation to the
//  LICENSED MATERIALS, which is provided "AS IS", WITH ALL FAULTS.
//
//  ST does not represent or warrant that the LICENSED MATERIALS provided
//  hereunder is free of infringement of any third party patents, copyrights,
//  trade secrets or other intellectual property rights.
//
//  ALL WARRANTIES, CONDITIONS OR OTHER TERMS IMPLIED BY LAW ARE EXCLUDED
//  TO THE FULLEST EXTENT PERMITTED BY LAW.
//
//-----------------------------------------------------------------------------


/*
 * unit_test.c
 *
 *  Created on: 22 janv. 2014
 *      Author: michael adjedj
 */

#include "tomcrypt_test.h"
#include "tomcrypt_mpa.h"


static int ltc_test_neg(void) {
	void *a, *b;
	unsigned char buf[64];
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, NULL)) != CRYPT_OK) {
		return err;
	}
	for (i = 0; i < 10; ++i) {
		if (yarrow_read(buf, sizeof(buf), &yarrow_prng) != sizeof(buf)) {
			err = CRYPT_ERROR_READPRNG;
			break;
		}
		mp_read_unsigned_bin(a, buf, sizeof(buf));
		mp_neg(a, b);
		mp_add(a, b, a);
		if (mp_iszero(a) == LTC_MP_NO) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, NULL);
	return err;
}


static int ltc_test_add_neg(void) {
	void *a, *b, *c;
	unsigned char buf[64];
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, &c, NULL)) != CRYPT_OK) {
		return err;
	}
	for (i = 0; i < 10; ++i) {
		if (yarrow_read(buf, sizeof(buf), &yarrow_prng) != sizeof(buf)) {
			err = CRYPT_ERROR_READPRNG;
			break;
		}
		mp_read_unsigned_bin(a, buf, sizeof(buf));
		mp_neg(a, b);
		mp_add(a, b, c); // at this po�int c = 0
		mp_add(a, c, b); // b = a+c

		if (mp_cmp(a, b) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}

		mp_add(c, c, a); // we will check that 0+0=0
		if (mp_iszero(a) == LTC_MP_NO) {
			err = CRYPT_ERROR;
			break;
		}

	}

	mp_clear_multi(a, b, c, NULL);
	return err;
}

static int ltc_test_copy(void) {
	void *a, *b;
	unsigned char buf[64];
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, NULL)) != CRYPT_OK) {
		return err;
	}
	for (i = 0; i < 10; ++i) {
		if (yarrow_read(buf, sizeof(buf), &yarrow_prng) != sizeof(buf)) {
			err = CRYPT_ERROR_READPRNG;
			break;
		}
		mp_read_unsigned_bin(a, buf, sizeof(buf));
		mp_copy(a, b);
		if (mp_cmp(a, b) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, NULL);
	return err;
}

static int ltc_test_set_int(void) {
	void *a;
	unsigned int b;
	unsigned char buf[4];
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, NULL)) != CRYPT_OK) {
		return err;
	}
	mp_set_int(a, 0);
	if (mp_iszero(a) == LTC_MP_NO) {return CRYPT_ERROR;}

	for (i = 0; i < 10; ++i) {
		if (yarrow_read(buf, sizeof(buf), &yarrow_prng) != sizeof(buf)) {
			err = CRYPT_ERROR_READPRNG;
			break;
		}
		b = (buf[0] & 0xFF) << 24 |
				(buf[1] & 0xFF) << 16 |
				(buf[2] & 0xFF) << 8  |
				(buf[3] & 0xFF);
		mp_set_int(a, b);
		if (mp_cmp_d(a, b) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}
	mp_clear_multi(a, NULL);
	return err;
}

static int ltc_test_count_bits(void) {
	void *a;
	unsigned int b;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, NULL)) != CRYPT_OK) {
		return err;
	}
	mp_set_int(a, 0);
	if (mp_count_bits(a) != 0) {err = CRYPT_ERROR; goto end;}
	for (i = 0; i < 20; ++i) {
		mp_set_int(a, (1 << i));
		if (mp_count_bits(a) != (i + 1)) {err = CRYPT_ERROR; goto end;}
	}
	static struct {
		const char *str;
		unsigned int bits;
	} tmp_array[21] = {
			{"A262452026EC56EB",  64},
			{"4E3E24506BAD88F1",  63},
			{"52B4CB6FDCF2FC01",  63},
			{"A4BAB4B2CFE0F15C",  64},
			{"A4BAB4B2CFE0F15C",  64},
			{"42E14B83E4CEF5F1",  63},
			{"CE468E9348D34090",  64},
			{"AB57F185A4AC63DB",  64},
			{"DDE1ED2CE0216A5D",  64},
			{"F5E7447C102026AE",  64},
			{"5940E91438D725E0",  63},
			{"D2B5E6B8428E63384580A1909FD3",  112},
			{"1F629132D169638C99BED939",  93},
			{"23256A481939E8FE087FB9432875",  110},
			{"D58B81",  24},
			{"04BBBD2E73E4B1CE76EDA88F",  91},
			{"15",  5},
			{"010FA14334E938B9CF9D9F87D9FDCD",  113},
			{"0127407F95",  33},
			{"0FC1669752C6610E4E7594BFAB",  100},
			{"01797B0E6A26805B309986C4",  89}
	};

	for (i = 0; i < 21; ++i) {
		mp_read_radix(a, tmp_array[i].str, 16);
		if (mp_count_bits(a) != tmp_array[i].bits) {
			err = CRYPT_ERROR;
			break;
		}
	}

	end:
	mp_clear_multi(a, NULL);
	return err;
}



static int ltc_test_cnt_lsb(void) {
	void *a;
	unsigned int b;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, NULL)) != CRYPT_OK) {
		return err;
	}
	mp_set_int(a, 0);
	if (mp_cnt_lsb(a) != 0) {err = CRYPT_ERROR; goto end;}

	for (i = 0; i < 20; ++i) {
		mp_set_int(a, (1 << i));
		if (mp_cnt_lsb(a) != i) {err = CRYPT_ERROR; goto end;}
	}
	static struct {
		const char *str;
		unsigned int bits;
	} tmp_array[20] = {
			{"034F30E9E786C81FC00000000000", 46},
			{"480F81294DBDA098000000000000", 51},
			{"D742AD5CF8456330", 4},
			{"0BD7D81ED89023F5000000000000", 48},
			{"087D5C6B9125644C00000000000000", 58},
			{"0625E2DC4646743D", 0},
			{"3AAC049EBDEDC850000000000000", 52},
			{"2E895911AA09E95400000000000000", 58},
			{"581820BDFFA9FE900000", 20},
			{"070A1296D049EA9D0000000000", 40},
			{"09D8EB7587A7AA530000000000", 40},
			{"03BE8E02495D8A3100", 8},
			{"7FC76B523F8DDE100000", 20},
			{"11ABA2E8DBA40E440000", 18},
			{"05B04B82FC80F94E8000", 15},
			{"9201C4DFB4926FC0000000000000", 54},
			{"8B90BD27558509D0000000000000", 52},
			{"039FFA35199631F10000", 16},
			{"A8894818802278A000000000", 37},
			{"0BE48C2012FC7EBD000000", 24}
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str, 16);
		if (mp_cnt_lsb(a) != tmp_array[i].bits) {
			err = CRYPT_ERROR;
			break;
		}
	}

	end:
	mp_clear_multi(a, NULL);
	return err;
}

static int ltc_test_2expt(void) {
	void *a, *b;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, NULL)) != CRYPT_OK) {
		return err;
	}

	for (i = 0; i < 20; ++i) {
		mp_2expt(a, i);
		if (mp_cnt_lsb(a) != i || mp_count_bits(a) != (i+1)) {err = CRYPT_ERROR; goto end;}
	}
	static struct {
		const char *str;
		unsigned int bits;
	} tmp_array[20] = {
			{"80000000", 31},
			{"800000000000000", 59},
			{"2000000", 25},
			{"10000000000000000000", 76},
			{"4000000000000000000000000000", 110},
			{"4", 2},
			{"80000000000000000000000000000", 115},
			{"80000000000", 43},
			{"10000000000000000000000000", 100},
			{"10000000000000000000000000", 100},
			{"2000000000000000000", 73},
			{"1000000000000000000", 72},
			{"80000000000000000", 67},
			{"2000000000000", 49},
			{"2000000000000000000000000000", 109},
			{"1000", 12},
			{"200000000000", 45},
			{"40", 6},
			{"400", 10},
			{"200000000000000", 57},
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str, 16);
		mp_2expt(b, tmp_array[i].bits);
		if (mp_cmp(a, b) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	end:
	mp_clear_multi(a, b, NULL);
	return err;
}

static int ltc_test_toradix(void) {
	void *a, *b;
	unsigned char buf[64];
	char sA[(sizeof(buf) * 2) + 1];
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, NULL)) != CRYPT_OK) {
		return err;
	}
	for (i = 0; i < 10; ++i) {
		if (yarrow_read(buf, sizeof(buf), &yarrow_prng) != sizeof(buf)) {
			err = CRYPT_ERROR_READPRNG;
			break;
		}
		mp_read_unsigned_bin(a, buf, sizeof(buf));

		mp_toradix(a, sA, 16);
		mp_read_radix(b, sA, 16);
		if (mp_cmp(a, b) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, NULL);
	return err;
}

static int ltc_test_add(void) {
	void *a, *b, *c;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, &c, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str1;
		const char *str2;
		const char *res;
	} tmp_array[20] = {
			{"86BE92979876D22AB7A642B35A91AE", "359C5C03019EBA57C292B84C45DA18", "BC5AEE9A9A158C827A38FAFFA06BC6"},
			{"8331801C30A80617551C3782742276", "BA745B46343CF47A747969B4D8AC31", "013DA5DB6264E4FA91C995A1374CCEA7"},
			{"BD0D498E832D1A8C986E8E7AC63117", "85C4609F6D2F229434A02A75ECED77", "0142D1AA2DF05C3D20CD0EB8F0B31E8E"},
			{"B338A219F9E90E9EE63FD7400F4815", "7E2FB75BE3D01C39BCC55B5F1F0D2A", "0131685975DDB92AD8A305329F2E553F"},
			{"F550C826E1D6F5EBC8AA160329ECA7", "AE206BDAB8EE0E0769C5B8CF39D15B", "01A37134019AC503F3326FCED263BE02"},
			{"B264BF569B3261D2EBDC1BA4C88205", "F343BCA8A2306ACCE71E26F3A90BBF", "01A5A87BFF3D62CC9FD2FA4298718DC4"},
			{"C86A83D3C53A5CD01236B9773E90F2", "6BF0C1AAFD00A1C0A5659A2C01BBCD", "01345B457EC23AFE90B79C53A3404CBF"},
			{"F8EA984C204ECE149D71536DA963AA", "80231AF45AF8A8CECC69E92AAE89AF", "01790DB3407B4776E369DB3C9857ED59"},
			{"9DF1B95EC8B8175999CFDCCBB8FC6D", "C3BDC77B52E5B756DE7EF5683B2F0A", "0161AF80DA1B9DCEB0784ED233F42B77"},
			{"5CDF96503C3E796A9FF70C3EA3FB65", "FB5202ED9498303D53C4DA7AA60888", "015831993DD0D6A9A7F3BBE6B94A03ED"},
			{"EEE635FF949BB3CC0D6377334891F8", "EEB09D9EE371AE0ED15B60A6BE98F9", "01DD96D39E780D61DADEBED7DA072AF1"},
			{"492036982EB5F79BD6C41DAA5A335F", "E941937D89F1595D57883E1875D791", "013261CA15B8A750F92E4C5BC2D00AF0"},
			{"E66C4554240CAA4878FDACB2DADD6C", "808D5851BA1EE3DAD8AF76F4A6E0C6", "0166F99DA5DE2B8E2351AD23A781BE32"},
			{"5C3AC188988481BA177F860BEEB92E", "FC3BDCC2AD0A7B1C96AFAF3042598F", "0158769E4B458EFCD6AE2F353C3112BD"},
			{"DF6108AFDA82830CF624E5F05595DC", "DD10C9953148F3ACDDF019A9D96D1E", "01BC71D2450BCB76B9D414FF9A2F02FA"},
			{"282838D8D65993D408C1593C4CCDE2", "D046BF88D0723BD4D2A2AC02531E25", "F86EF861A6CBCFA8DB64053E9FEC07"},
			{"BAB64A57A23E1071F2BB65FF838FE7", "B2A8FD42121C42BB5B2010B74BEC", "BB68F354E4502CB4AE1686103ADBD3"},
			{"103AD57C5E3639526AB921C655332E", "FACCAA04F3360BCB79244BFD5AD154", "010B077F81516C451DE3DD6DC3B00482"},
			{"FB743CD3D6724F2025B2C38E6D46", "25051382AAE6E199AD4F3CD3FE497B", "260087BF7EBD53E8CD74EF978CB6C1"},
			{"82FDD9396B8FDA2DFDD351F6B939B1", "C81E91B43B0A590CA184DBE6EEFDD7", "014B1C6AEDA69A333A9F582DDDA83788"}
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str1, 16);
		mp_read_radix(b, tmp_array[i].str2, 16);
		mp_read_radix(c, tmp_array[i].res, 16);
		mp_add(a, b, a);
		if (mp_cmp(a, c) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, c, NULL);
	return err;
}


static int ltc_test_add_d(void) {
	void *a, *b;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str;
		unsigned int integer;
		const char *res;
	} tmp_array[20] = {
			{"78BE2B0513EF6D8DA938BE94E1798D", 1912879528u, "78BE2B0513EF6D8DA938BF06E5B335"},
			{"9CE6ECE41EE8D0C6C1DB1B7DF79C15", 37203308u, "9CE6ECE41EE8D0C6C1DB1B802F4981"},
			{"F02359AD5F68582EDBCF37991698F0", 2020185834u, "F02359AD5F68582EDBCF3811802FDA"},
			{"BDCFF6CF46CF044C006C7D29F8E191", 3150062353u, "BDCFF6CF46CF044C006C7DE5BB04A2"},
			{"B13DE33B39ACAFF836E658EB6BA917", 4100301709u, "B13DE33B39ACAFF836E659DFD14CA4"},
			{"9CD3710925545E9EB4759AC910BB34", 2444148406u, "9CD3710925545E9EB4759B5ABF79EA"},
			{"C2542F27B923E97B853D9642D1E3BC", 1209618026u, "C2542F27B923E97B853D968AEB3226"},
			{"9B22C19322DB458E913D951927DF8B", 539548887u, "9B22C19322DB458E913D953950BC62"},
			{"18252DE0D0680A46C0F665A4C38BE8", 796489082u, "18252DE0D0680A46C0F665D43D0162"},
			{"4D69CB0D5DF17584988A1530F114BE", 1420558864u, "4D69CB0D5DF17584988A15859D16CE"},
			{"E3BBB7102229B645755AC3D7E57A13", 816322096u, "E3BBB7102229B645755AC4088D9043"},
			{"488432BD3613670EF6B188B46B2BE4", 2256072767u, "488432BD3613670EF6B1893AE41C23"},
			{"F24239E03FF801B58D117D0E4B82CC", 3020577677u, "F24239E03FF801B58D117DC255DE59"},
			{"58253EDE625CA5679DFAD78812A94F", 2888525486u, "58253EDE625CA5679DFAD8343E0FFD"},
			{"E80953D6F4751CDD6BAE174F4E4BF4", 1860846378u, "E80953D6F4751CDD6BAE17BE388F1E"},
			{"AB55B98542F6DD82207C38CC1A3186", 2785552020u, "AB55B98542F6DD82207C397222581A"},
			{"27650B8E53B733C8E673087E99646A", 2686262100u, "27650B8E53B733C8E673091EB67FBE"},
			{"3458536138CAF2BB856CA11792CD69", 2938349192u, "3458536138CAF2BB856CA1C6B673F1"},
			{"BF656E0EA483A34FF694AF4B8149FD", 1514764810u, "BF656E0EA483A34FF694AFA5CAC407"},
			{"51E217AFD00ED287E85236E81A32C6", 4042393042u, "51E217AFD00ED287E85237D90C3898"}
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str, 16);
		mp_read_radix(b, tmp_array[i].res, 16);
		mp_add_d(a, tmp_array[i].integer, a);
		if (mp_cmp(a, b) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, NULL);
	return err;
}

static int ltc_test_sub(void) {
	void *a, *b, *c;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, &c, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str1;
		const char *str2;
		const char *res;
	} tmp_array[20] = {
			{"843B0A08009ACE5CBE73B9B9B2A565", "B9D52A966F2C1C27D23F8BDD1D8A53", "-359A208E6E914DCB13CBD2236AE4EE"},
			{"D131433C5200AEAE6560A8A2F665CA", "85385C60207B171463E135E09892D7", "4BF8E6DC3185979A017F72C25DD2F3"},
			{"4DD65F5C02965716C96260E6F7C0E3", "984FADDF868220BF8346AE350FBE8E", "-4A794E8383EBC9A8B9E44D4E17FDAB"},
			{"3509DA0ED0177D666D8E9DF07C4AB6", "13C4B40F5F22C78411E42CBE6A156C", "214525FF70F4B5E25BAA713212354A"},
			{"37951D81A2CD204117D96DE2253E1E", "DC656CE25B647B2C8DF8B369D7CD60", "-A4D04F60B8975AEB761F4587B28F42"},
			{"50E09E18893EB0EC66C709595E8532", "72428A25C1AD51F12EED2E9DCEB36C", "-2161EC0D386EA104C8262544702E3A"},
			{"23E6DFB591FBEC4421E589ED2DAF9D", "436A4D14A71FB772C5CBD22D4FBC7D", "-1F836D5F1523CB2EA3E64840220CE0"},
			{"1B297841A5158284976987C04EEEB2", "1FC466636118646CCB6ADBE7679CC0", "-049AEE21BC02E1E83401542718AE0E"},
			{"8D46CF02736C2A5C3AAC49A3EFAE7E", "26C34AD1C3F3066222B014807C373C", "66838430AF7923FA17FC3523737742"},
			{"F70A82D504045B32F51ED0806DDDDC", "59B8529A6FBB742DCE086F91C44078", "9D52303A9448E705271660EEA99D64"},
			{"4C25D00BFD5E237A24F0A2A4D258BF", "2B715FD6000671FB437B5BE40BC326", "20B47035FD57B17EE17546C0C69599"},
			{"37A1B4908E8F3675D0E8F4847647EB", "9F118CA253113864177567CB3D66EB", "-676FD811C48201EE468C7346C71F00"},
			{"4A8B21FAD33051C069D34CEE9191A3", "6A3B2C0422E11AF8C8341A868E8339", "-1FB00A094FB0C9385E60CD97FCF196"},
			{"B23F449A7CFBEF420A21770D998415", "2BB663FB93175AC5847E5621AC90FD", "8688E09EE9E4947C85A320EBECF318"},
			{"9DB472876ABA7160D68B26C5146C10", "9EDF8BE01934AA1A04F074B16FE491", "-012B1958AE7A38B92E654DEC5B7881"},
			{"BE618780C31DA411E911DFC7A63B99", "CA3A3CE473F67B0842D464E7F93739", "-0BD8B563B0D8D6F659C2852052FBA0"},
			{"4DC88256DF0C01EA0D04FA97D3ED5F", "79591A3A73B25C7309C814361C941D", "-2B9097E394A65A88FCC3199E48A6BE"},
			{"C722C7EA75752D260DAA59BF27FC79", "BF3C9A11FBB551FEBC439AF851DFA5", "07E62DD879BFDB275166BEC6D61CD4"},
			{"98D36489C57AEABD9DEDD1FCDCE33C", "752D50ED4E379CC5A7571C841C1FBF", "23A6139C77434DF7F696B578C0C37D"},
			{"9BC66E62450D9C3DA5B02D72F8363A", "A5F3B1325E5964FF153FD9D880A92C", "-0A2D42D0194BC8C16F8FAC658872F2"},
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str1, 16);
		mp_read_radix(b, tmp_array[i].str2, 16);
		mp_read_radix(c, tmp_array[i].res, 16);
		mp_sub(a, b, a);
		if (mp_cmp(a, c) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, c, NULL);
	return err;
}

static int ltc_test_sub_d(void) {
	void *a, *b;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str;
		unsigned int integer;
		const char *res;
	} tmp_array[20] = {
			{"C18E9E9ACEBB4F6C9315BAF053D69D", 2638101586u, "C18E9E9ACEBB4F6C9315BA53159A4B"},
			{"0D4F03475A07A056E912773832DE6B", 3472730280u, "0D4F03475A07A056E91276693535C3"},
			{"5DC471BB0FD6D53F040B4DCA9CDBE7", 1191140014u, "5DC471BB0FD6D53F040B4D839D8139"},
			{"819E71427DA2FC02A41B4FFC875F1C", 3609952152u, "819E71427DA2FC02A41B4F255BDF84"},
			{"31C7683D9EC2E22F5C0468DC805B3F", 2513589668u, "31C7683D9EC2E22F5C046846AE059B"},
			{"503F8DD770549DBA1324D2D39BD6C9", 423448098u, "503F8DD770549DBA1324D2BA5E88A7"},
			{"2ADFF9623F7FF41F45CC3E4EDDA88B", 1912548955u, "2ADFF9623F7FF41F45CC3DDCDE7A30"},
			{"49E7FD71ECCE474E88CF204684F1F5", 3912730988u, "49E7FD71ECCE474E88CF1F5D4D6889"},
			{"DCB318D38C9F3E0F546BBACBF335AB", 2393714618u, "DCB318D38C9F3E0F546BBA3D4605F1"},
			{"9DC89C75395B76827DA4E75DEDA9EF", 238923757u, "9DC89C75395B76827DA4E74FAFFA02"},
			{"4D5EDBE5DB8BD56CE37F5B9521B38E", 3908550119u, "4D5EDBE5DB8BD56CE37F5AAC29F5A7"},
			{"10DAFA895E8FB0C24D4D87AA3FB504", 866824364u, "10DAFA895E8FB0C24D4D8776950458"},
			{"72049DDDB654335017831DB7C28C70", 3103619117u, "72049DDDB654335017831CFEC51443"},
			{"C0BD90EA333EA0DDFC054B951F8C91", 4139013158u, "C0BD90EA333EA0DDFC054A9E6B386B"},
			{"3B35674422A4126FA7C5C9B93ACBEA", 3855630932u, "3B35674422A4126FA7C5C8D36A8996"},
			{"B9C8C7A0604D9369BD879A51903A1A", 3736267496u, "B9C8C7A0604D9369BD879972DD4F32"},
			{"7FB12C7F45FCA325257665EBAF1CC3", 2157346092u, "7FB12C7F45FCA3252576656B189F97"},
			{"9626C3F775690D606C0FF3CED39239", 1454912899u, "9626C3F775690D606C0FF3781B5CB6"},
			{"4649A1BEB3EAB48A4962A5D940F672", 3521305441u, "4649A1BEB3EAB48A4962A5075E1B11"},
			{"6DBA08437449C09F277CB24405C236", 1272246752u, "6DBA08437449C09F277CB1F830D056"}
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str, 16);
		mp_read_radix(b, tmp_array[i].res, 16);
		mp_sub_d(a, tmp_array[i].integer, a);
		if (mp_cmp(a, b) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, NULL);
	return err;
}

static int ltc_test_mul(void) {
	void *a, *b, *c;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, &c, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str1;
		const char *str2;
		const char *res;
	} tmp_array[20] = {
			{"B70C24FB5F7836F873D25E5915191F", "797F9003DBE1E68F01AF74B6431C91", "56DFF37ABFFEED6F27260AC9E146C586317213373CCBBA7D5C9C60CF9E8F"},
			{"0B965400E39B8276832A294D06A756", "CF8F44D35F14F122473289C57F32E8", "09650A03240F176192E3D5508039E5AFB2F608ED441211F5F4914C6071F0"},
			{"5850B4D68897F12B32C83AEE7BB33C", "F7B96AFE992CB0DCF0F906AD58E172", "5575D5B6EC9F37DF6826D14ECE13F369D52E6E5039B9068017E6143D8CB8"},
			{"3DA1E7A6E0F833AE456C5F6A102FE2", "45982F1859F85E280F74CC123EAC83", "10C146E81C16E94BD6E5934EBD9A6D0F95245724AD79BFBDF377A33058A6"},
			{"D9AE5BBE2BDB76111F67C603D0E8AA", "25E59048FA21458DDAC80508E17E15", "203966EAAEC949BF07213EB4B5A68F074C0D0BA4CEAC4D6C3652F010C1F2"},
			{"2CE03008981952C91C996C7FC38623", "E70DB18FB2EB22BAF359DABCBCBFF1", "2880B1DA637C723BC2F902F067857E2678BAE683F32B8B41315D5DD963F3"},
			{"0179DE431A0D4552966DA9E565A1BC", "130F72055F3DE041426CD62691BF3D", "1C224B4DC550A57B98694E4F1076512814C5EC992F509A6B5D005ECDCC"},
			{"5EC49F6E7ADCE400B1C953D82ECB77", "DD7DAFAEFF50D6304394EBEB412CB6", "51FE44AD6A27594F89E250FC546EC868F62DC52683FD3376F5A8A2741A9A"},
			{"BA1429C4210CE0C6FFDB8CDB69B74A", "BF7062EB6EE5580669BE4A4BEF0264", "8B26BBE27391DAFF4F2957ED7CAD7C6B7DEE31143533C463948554D02CE8"},
			{"A9C5E20A0D3E5B4A348214DC5C1E0D", "DAB79A667097874DAC3C0557A8FBA2", "910C45561DF3BDA0D32F756CA4F7890B976E96723707E3EC522CE749C33A"},
			{"79B7E68C50FA2E35C48DC43D28746C", "30788DE46BC9A6EDC79DCBABBAA15A", "170BCCE545F939A0A00009627BF03661843F380C6BF1641F4440ABE8D9F8"},
			{"45FB9E2127742B26EC4E395F823CCE", "3C135492047A1E0177C051E972FB38", "106C41DAFC51882CB559E963757C454A68F0C41C1CBB396F2BB627D74710"},
			{"E13929EC91D0797C7DA0B969F5B716", "453CE8EBD86B738DE213E4E4030983", "3CE9FE9DE29E01D771A247D73E450F71E2ED029285CD7E548A23996E7642"},
			{"FF1DFF1FDC130D7DA1F1C19218AA1C", "C9C3143A50E2C394FBA58F559987BB", "C910F551CE653DA1C49271A76122DA2899EE40D37D4F68DA3F4DB0750674"},
			{"31C02B09E12B7DC76D630709F3CB14", "5120DB0A30F2138C63C8BB1904A5D2", "0FC43034E1511DC5E81320EB5B53752D1E42886E87D5891CB3706C307A68"},
			{"506B49B08790C08D7C7BF8BFC0134E", "67A1C15317AA830D505F627F806BCB", "208DFADA5B56ADFAFBF9DC509545F0E0882AF8B6E1DE4A18C5DEAE60E8DA"},
			{"E93DF474B6786F79EFE3B433A844D2", "02F8307200C360B023A811F1D18244", "02B49C11369C7603B430191BD602EF5C55438976E0AD6425F5350D16EBC8"},
			{"EC6A3360BB3548AB9C49B50661825F", "2915CF2E849FE89A7A2B468AD99130", "25F126458A05C606DC5257211386F6D6C0E359F0479929C5EE7725A740D0"},
			{"B24690D77954E2E0DEEC97F0609031", "5ED75F4B754EB4D127C4EF06FAE9D3", "420BE4CF7FA1865E0A066C6D145347B1ECB3A2F943AE2A196E6FF8AD7163"},
			{"29583BF1C2087C2620152F710CDA2F", "1CADD60FCCC59ED9CF62CC21A56781", "04A1B9C142F2E2FFF17E8AEAD1B845914BA5A7451CBC289C2440D28DDAAF"},
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str1, 16);
		mp_read_radix(b, tmp_array[i].str2, 16);
		mp_read_radix(c, tmp_array[i].res, 16);
		mp_mul(a, b, a);
		if (mp_cmp(a, c) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, c, NULL);
	return err;
}

static int ltc_test_mul_d(void) {
	void *a, *b;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str;
		unsigned int integer;
		const char *res;
	} tmp_array[20] = {
			{"1BD7F2599CB558A8145A1A149C1568", 575098425u, "03BA6F961C96CFC50EB59013F47437E51E7428"},
			{"5463DDC2D243CCB976F414641FEB5A", 1093369850u, "157BB244ABA6BEEF7320E34E1965B3FF0B7BE4"},
			{"477CF56986A9428600CD66DA961D7C", 1266272257u, "15139DCFD08BA31B7634815E2073C3653AFD7C"},
			{"F47FF633460FBBC624D35BC5EFFC13", 2388753994u, "87FC17AA6274AD6C0D78FE643D61B462A3377E"},
			{"E1AF86DA155390D8E31AE850A11578", 3694383486u, "C220868AA9427ADFF6C2BA2A5166B598B78910"},
			{"60B3F732E32749D57704DD767750DE", 2762944078u, "3E3576E0628EE97A7E6854A06BB22208A487A4"},
			{"8E3B61227F361FA2667A3B9FB4C653", 1205681345u, "27ED62F491982551F0D64782AC2272006BF893"},
			{"EFBB5AC4DC54780101A6343FC426BC", 2117046459u, "762AC19B0F80104EFC3354E4AC0C1C8E960B54"},
			{"4D0B949E45144CF3B852C60E245793", 2679242357u, "300FC2E4C21553B44A9ED68316B0115F22E02F"},
			{"9D1418CF00E16EF07F3736132318D7", 2876840455u, "6936BB0A557FB368001477B66D7D9A711A83E1"},
			{"6C78E6B7508080DA7E4083D6FF8A2F", 642621302u, "103AD62DB21C7D461BB8A619D538AD5ABFE2AA"},
			{"8FC380E176D2DE00B72EDCACE02A82", 1969400383u, "41EBC25996504C93954FA69DAFB4591728C9FE"},
			{"BD1D3BD7DBB35116C8F8734BDBD4B8", 1471750368u, "40CDB1BFBBB70D7AFECD77C90155851BE92100"},
			{"878CE8412A45FE444F3900BE5D66CD", 3931331339u, "7C12EF2FC761D3EF92F3FF41E9CEF3180549CF"},
			{"86EEA9F5CDCDCBA7FB6CD363909C91", 921679158u, "1CF4B02DBA6730727B43696354DF0500928B96"},
			{"7D1EED36B38F7F338EDA782662AC1E", 3360147505u, "61E33EBEA2B20BED08BEECEE556AD19BAC61BE"},
			{"BF41AB1D5134D8F695581FEB5A2905", 1132736647u, "3270F1E613156FB823C7B7D455682F79D091A3"},
			{"5710600F57F3039861C5077A586EEF", 691229558u, "0E03140808D5B1937332186307C77F71579F2A"},
			{"1636FBCE02F890343F2741286FE037", 1766339541u, "0922D13DC112560DFA2340D146E6B28D3882C3"},
			{"2EF9D89C5D1790A70F27BF3469CEB0", 3030733559u, "2126028FE8AEA6951066CB1971C5CB6DBACBD0"},
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str, 16);
		mp_read_radix(b, tmp_array[i].res, 16);
		mp_mul_d(a, tmp_array[i].integer, a);
		if (mp_cmp(a, b) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, NULL);
	return err;
}

static int ltc_test_sqr(void) {
	void *a, *b;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str;
		const char *res;
	} tmp_array[20] = {
			{"A2C775A89A803C4C073409AE54ED6C", "67810C5185BE0BF253FC3A4E88901DE27C7BADC92F6D550C20837B112590"},
			{"73DBD800EC5B4BFBBFCA9B00BF6862", "346F40DC1C2FF953197B743509F5E969C29EE02844C1E6BF9DC8ECCBC584"},
			{"83B152D9242AEBD3E6E3BD04BDF9B3", "43BEF59DE617C40ECE46010B61E0456971A8531D9B94A910A1163DDBB329"},
			{"CC40A4C991E9B3B0279FC244B4E21A", "A2F716F40F684CE4799ADDC7AE14CDA41DCF7D580F21895F93548C41EAA4"},
			{"0F74F6636E2C202AE414C6C97F0618", "EEEA4FDE28421D60F664E40865D67C06FC145E081AE2C9E3B8BBF52240"},
			{"F3AD2CB5D2732A4771BD21047E7A0C", "E7F23806A3141365A0E043993ABEDEEA66852234B82F4F7D6164BDFF7090"},
			{"47C6A532CE28CFF8B39552AD495C28", "141FC9C6238C1253726028B28D56D8BFF6C57245583F3D81D533BFFCC640"},
			{"84018C7ABF28CF9F4F90E46748B926", "441198E0FB2E105D4E0619DBDE9E4287DCE8B771204D6CF425553F47F1A4"},
			{"695FAB90CAC620EC25752C3BB7554B", "2B5F9E7D8EC7C6D7957BB4401A42512EE66C22A6153B1897E4639FA4E3F9"},
			{"E949A908C81AD0E919F4A39ED34A6E", "D4972AE3D2DF8813FC1ADB6E5EE70D5B681FB7313CD72EF7F6578EF7C744"},
			{"F27D771F6223E4109D24542DE5C7BC", "E5B172B4E19FE35269AA5263B0577499D29323FDFC4543CA89D70A2DD210"},
			{"7D24C50F530C8FD2152C6ABFB44EF5", "3D2CEDB8FB1A36B7C786A9D219B888E03D186F71513E343627B4B6E23679"},
			{"CCE4432C2D208BDAF1BC4988BE0BE8", "A3FC9696203C681CA39BCFAECDCC782055533ABE25FFF1BA040C2CEDC240"},
			{"29ADFAD58DAB3A96F8427C4D3B8E96", "06C9309561C81D09075542D9577182DF7603C950C2A1A9245AF1448EBFE4"},
			{"0A841BB426D8C241A7B42D4B05DCF7", "6E9656A7D07DADD47F1C4048BCE469F32E1D184BBB6D0976711A5F7651"},
			{"D15F3D3E75ED35806316ABEA49314B", "AB3CA56E7F8FAAD9B7CC57A465C655F1B2865F63ACAC88ACA13C4243CBF9"},
			{"C5F1577EA1D09449DB254829A183D8", "990D542EBF5EFF9052BA2D5F3444D57ABDB30552B9A8E54BBBA24996C640"},
			{"B982E44741974AB91F8491A0C17D49", "866E70DBA0BA48526364FD4D1C0EC301451928FDA2C2E303A38B65625ED1"},
			{"AD0D423E1AE00B44EEE2D1AE9BA60D", "74FAEC37BBC59EE8DD06195DADBCF3E203BF563542C70A9809962B72DCA9"},
			{"5771AD736F3A5BF27B9BF58F3B76F8", "1DDE765F0B071465FB1D208C0CF71BD171AA41064B5EAC5583691D999040"},
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str, 16);
		mp_read_radix(b, tmp_array[i].res, 16);
		mp_sqr(a, a);
		if (mp_cmp(a, b) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, NULL);
	return err;
}

static int ltc_test_div(void) {
	void *a, *b, *c, *d;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, &c, &d, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *dividend;
		const char *divisor;
		const char *quotient;
		const char *remainder;
	} tmp_array[40] = {
			{"34B3716544C969D558DF9921765ABE", "8DDC2C232E1C6B18613C251E815C67", "0", "34B3716544C969D558DF9921765ABE"},
			{"A8E160DF073185B48FEB2ABECEE412", "3E696361E8D4AD8E4B7121AB0B0A5A", "02", "2C0E9A1B35882A97F908E768B8CF5E"},
			{"C2810789FFDDA612928BEE9B53A5F1", "C925F4B8091CB2EE7B7138837D536A", "0", "C2810789FFDDA612928BEE9B53A5F1"},
			{"BF2485CB9DE74D013F2DEBF6B056DE", "1F0B3932669B0D9E291CBECD95035E", "06", "04E12E9D3644FB4C488173253242AA"},
			{"9AE071FF783DEB6FDEA63090201138", "DA43610E9841CC69DEED6E889F75AD", "0", "9AE071FF783DEB6FDEA63090201138"},
			{"133594B769AA2953C12E6A03534DEB", "99A7BA5CE77B7124B86A6A92A54F69", "0", "133594B769AA2953C12E6A03534DEB"},
			{"F64EF511CAD89829C0C54A628B20E9", "A3C10CA955539E51A564B7BBD2FF1C", "01", "528DE8687584F9D81B6092A6B821CD"},
			{"F7755D0D584903C73E505BC9C304BB", "EE7BF8625FA68CCD6315649B97165F", "01", "08F964AAF8A276F9DB3AF72E2BEE5C"},
			{"D21C3238D7FC3A3D8535D59E6EA7F6", "F0969F901C475ED8E12BFEC3EF8C15", "0", "D21C3238D7FC3A3D8535D59E6EA7F6"},
			{"AD14B8996880786D492769F3E72214", "2360C3DF341C88D61A52A0D943E5EF", "04", "1F91A91C980E5514DFDCE68ED78A58"},
			{"57F23562C0E4F840822EEA48E7E555", "7AFC39879BBD85CA877CF74F6676E0", "0", "57F23562C0E4F840822EEA48E7E555"},
			{"9AD6E642F9D9174B0E6D56440EF818", "8D4A205D932FF73E272C1D9FBD81E9", "01", "0D8CC5E566A9200CE74138A451762F"},
			{"23F24A17237F481FBA123F42C17D97", "0A8A6AA1F7AD3BE58469815A3AAEF5", "03", "04530A313C77946F2CD5BB341170B8"},
			{"73149B971FA0D65B2C3BA65A09E25D", "66E0B25E16BFF09594BBD8A242472B", "01", "0C33E93908E0E5C5977FCDB7C79B32"},
			{"820A585C843F5BCC07D8ED7204D3BA", "8E10E29A6AC804F1CA6F01CBD1B3BA", "0", "820A585C843F5BCC07D8ED7204D3BA"},
			{"7898E6F68DDDD24A9FBA576DAC458A", "CD9DFA5F4B69BB674C64BE761E999D", "0", "7898E6F68DDDD24A9FBA576DAC458A"},
			{"61FB446B58B6DB80885F3DE7E51CC0", "960E7EC6DA1BDB02324D74D8F9BE3C", "0", "61FB446B58B6DB80885F3DE7E51CC0"},
			{"0C212FF4184DC212D40FD563DF4E41", "2C396013D89785081C6F6E9876CEDF", "0", "0C212FF4184DC212D40FD563DF4E41"},
			{"5B0AFB27FB2481E8B4AD8039C1A468", "6AC8D9BC6F9BAB085F9E607CC1353F", "0", "5B0AFB27FB2481E8B4AD8039C1A468"},
			{"5A2F809AE8CA57881DCFF552B1CB32", "EB812763D156258E4588D1748D2E6F", "0", "5A2F809AE8CA57881DCFF552B1CB32"},
			{"97D621C6BCFFA9077C7651BD76B57C", "016891D8AEF0F8890B8DA8DD29", "6BCD4F", "261852D45D37B5BC5D1DA0D5"},
			{"3CB1898441C5080C52C4E118CBD077", "080BDD0976B3BCED6C4E5DC280", "078B01", "0532025DCF45B5E45790528DF7"},
			{"A66210FE2E0B5F1A0FE1B2E2606AD3", "0290CDB75DE23EB5C1B2EC4ABF", "40D9BC", "026F343DF85B847BB681BD9F8F"},
			{"DCAE3E5B65A8D816AC21F84D14B026", "0239A027C23AE867374F6B008A", "632D87", "0170D6C5304195447667312560"},
			{"9C972AEE037E94D09644DEA8779794", "0D46FEBB0B42F696A2B635399D", "0BCB38", "055E7CC56C283476811E647E3C"},
			{"3021DA735E9C7220A9933ED7A2FD80", "04283B6EEB9AC18837A5F178FA", "0B9402", "0202A7E2D22E02357FBF11838C"},
			{"E4B38CA90CED65076E9D97F81F53E9", "08A29FAD617DDC2350FFD2912D", "1A7C10", "058B3015FAF257313B3E127519"},
			{"208349E03BEE7EE66EE3B9C0BB10B3", "0A7F8B7A8076D625BE18C35381", "0318D4", "BDBD0C75F85385B0F4A2D1DF"},
			{"B2E0644CA645402DA854145BFD4F8F", "05658405ADDDEFDC1ADA8E3621", "212580", "BA67B1522B7438BB8CCE7A0F"},
			{"D9A26DC52E42814AE2A8272521AC1A", "0A550766D35CB9A8378902973B", "151056", "094EEDE679BD726FB88CF82E48"},
			{"29CAC2304BD7B52FD08E854AD8B205", "04C1DAA0182DC27523C576E08C", "08C8F0", "04A5816F36B4E09F004798CEC5"},
			{"1CCBC1716D727AFCDE80E512635F1F", "0B6F10AC4DA82453ECE7FFEEDF", "0284BB", "015ECC3AC5C7353B37C586E63A"},
			{"DB05A44030099338B12CAC699A9AD1", "07DCD6E18A099E265FC4CF16A0", "1BDB22", "034F25FB559AC264BFBADEB991"},
			{"5E49C72E7E99E315341B4D6F4F62B4", "0B477411535103EC79AC847B69", "085C0A", "08232173651E43C0693A80D49A"},
			{"799C6D32B77E5E9AA8862E9AD2605D", "09CD814A7061817DA1919C1C2D", "0C67E2", "07445BFDDB8938C8A4ED8F65A3"},
			{"4D72D5B4BACEA1D203C90612D0DA0F", "01C6C53DF32BD52CCDE4087CFD", "2B98F2", "0149A57FED494FE1927A157AE5"},
			{"0D2B2B9DA9FC051D0E007573C44577", "096658B56B9E975AD155A55863", "0166A4", "05FF21434BDB1714955C3D340B"},
			{"8E34E3BCE8A2449B92A555E806CA0E", "C7EDACD38373F4A35A9F1CB9", "B616F1", "3AEF4D69F840E0A5803ED9E5"},
			{"CCEA69D7BB967C5A6A5810BDC956EE", "01E3BA5E49160DF407BF4AF00F", "6C7233", "B4C8F437CBB293B8FCA0D5F1"},
			{"1A02864421DDA61BA4BCDF7F09FC79", "05AF90A1CD38638813408DD738", "049314", "01F8B780AE6C6E0B15A4800419"},
	};

	for (i = 0; i < 40; ++i) {
		mp_read_radix(a, tmp_array[i].dividend, 16);
		mp_read_radix(b, tmp_array[i].divisor, 16);
		mp_read_radix(c, tmp_array[i].quotient, 16);
		mp_read_radix(d, tmp_array[i].remainder, 16);
		mp_div(a, b, a, b);
		if (mp_cmp(a, c) != LTC_MP_EQ || mp_cmp(b, d) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, c, d, NULL);
	return err;
}

static int ltc_test_div_2(void) {
	void *a, *b;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str;
		const char *res;
	} tmp_array[20] = {
			{"5A880BB7F76DC5688D4961AD4B0BBB", "2D4405DBFBB6E2B446A4B0D6A585DD"},
			{"B30CEAD3746512B73C02040D6844DD", "59867569BA32895B9E010206B4226E"},
			{"05DB6833C3479A58D9410EB100604E", "02EDB419E1A3CD2C6CA08758803027"},
			{"3AB4DDFD9E96115DE5EC532779B3C0", "1D5A6EFECF4B08AEF2F62993BCD9E0"},
			{"077B7029442F3FAF9AA2BB9DE038BD", "03BDB814A2179FD7CD515DCEF01C5E"},
			{"F32F7DF33B121894BB6CC25806C502", "7997BEF99D890C4A5DB6612C036281"},
			{"379F60C43D4519E9EDA846A1521023", "1BCFB0621EA28CF4F6D42350A90811"},
			{"608391B5AA4812C9B069D3196A223C", "3041C8DAD5240964D834E98CB5111E"},
			{"2638BE7E9F60494869EA28F0F162BD", "131C5F3F4FB024A434F5147878B15E"},
			{"5B976DF95542035BA953A7EBA4DCC1", "2DCBB6FCAAA101ADD4A9D3F5D26E60"},
			{"CB0513D358BA0F11AAF816126E686E", "658289E9AC5D0788D57C0B09373437"},
			{"64236DDE7513F93F42A570AC2DDFB1", "3211B6EF3A89FC9FA152B85616EFD8"},
			{"E37C38BCBC2E9ECF0DCE094DEBAA75", "71BE1C5E5E174F6786E704A6F5D53A"},
			{"08EE28D554EA0A6022C1B4A51CE8BE", "0477146AAA7505301160DA528E745F"},
			{"3C02126DEDDA0343822F36173B6B17", "1E010936F6ED01A1C1179B0B9DB58B"},
			{"89A58F70A9F2A394AA91501A893F18", "44D2C7B854F951CA5548A80D449F8C"},
			{"72F6E05E41C37E0E902D60107C28B8", "397B702F20E1BF074816B0083E145C"},
			{"0A91255A0D7D2E063E22C57F33A15C", "054892AD06BE97031F1162BF99D0AE"},
			{"EA16035028F0B8611B44EE12F7A294", "750B01A814785C308DA277097BD14A"},
			{"B10977732ECAF77EFAF6B84C0EDA94", "5884BBB997657BBF7D7B5C26076D4A"},
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str, 16);
		mp_read_radix(b, tmp_array[i].res, 16);
		mp_div_2(a, a);
		if (mp_cmp(a, b) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, NULL);
	return err;
}


static int ltc_test_mod(void) {
	void *a, *b, *c;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, &c, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str1;
		const char *str2;
		const char *res;
	} tmp_array[20] = {
			{"E3854B159468078634F689A36303B2", "C376E097F1E12B97976525356B445D", "200E6A7DA286DBEE9D91646DF7BF55"},
			{"-6C09610D5DC53AB7C02CB4FB2B35B2", "3F7ACCCA4CF4104CA8082C84A21ACF", "12EC38873C22E5E18FE3A40E18FFEC"},
			{"-6F9FA58761604803FCE51EE165D8BE", "FFA90B13EE050B46CA46CEA0882058", "9009658C8CA4C342CD61AFBF22479A"},
			{"09F46F62AE90B7461205EBDBF9B1D7", "2DE007FF22FAC64717E73AD76341CA", "09F46F62AE90B7461205EBDBF9B1D7"},
			{"F10B4B174F956B3D3D724BF99B0D11", "04D0011BAC20ABBED066FFDA3DDB92", "6B13AFB133DFF889545359862A8D"},
			{"-4BFB30796355295FAD0F4649078000", "3E31D9EEEE26839634F965AF4451BD", "3068836478F7DDCCBCE3851581237A"},
			{"DE08ACE5D11E8763AAF3E9402A181D", "23BCC9D78CBFC8FD664F06EDC485F5", "079BF1D8849FD1734519BFAD8EF45F"},
			{"6BA5A652551A2357AA38E1012FA32E", "0E910E03D083116EB81B3ADE41A3BE", "05AE4437A184A950A17A44ED6428FC"},
			{"99E01CB40C8B9CB0B19266398FC5FE", "B57CA666A503B9B08B4B66487D5EEC", "99E01CB40C8B9CB0B19266398FC5FE"},
			{"8D13215E7CD1F97B352F8688740F", "E45732291F643B1694BD6D4F55A8F1", "8D13215E7CD1F97B352F8688740F"},
			{"-BE3FA72CB3FF65E58E6C66BCA775AA", "734D8B0ABD85DA1642778AB096825D", "285B6EE8C70C4E46F682AEA4858F10"},
			{"EF1293B80E85E9AD0C73B17D5A841F", "5DA159448258B6547BF55610C7B343", "33CFE12F09D47D041489055BCB1D99"},
			{"-13659AF0AC5475ED7CC529539A3172", "3EB8CF026C1AC5C03F13FC826E51", "3425C01573E7DE96F115952847DE"},
			{"-A894D3A8F59FE4303E62FBEAF60745", "408AFE241749D9ADA9AD6015B945EE", "190C26C3503DA8D8BEA5245635CA85"},
			{"-8AAA567C1780274E935547E7731712", "1789B298B57BEC30D2CB0EDDCB278F", "028FD918296761D65D6D114B4FD648"},
			{"-7784002504D12DCD97C569E855B849", "A066FC7AC5E3954A98E9A1BF21DB43", "28E2FC55C112677D012437D6CC22FA"},
			{"-30382E761172600233AE48680CE502", "D4628C20B4DFFE5B8D09A7593D7B95", "A42A5DAAA36D9E59595B5EF1309693"},
			{"EC9C73E6143E6FF4A7A3A37C8B0AB7", "A4D92E66607D03601329F0AF0C1224", "47C3457FB3C16C949479B2CD7EF893"},
			{"-775A685CE500ADD1C67AD4862EC70E", "93A40E020FF434C4FCA7CDB9FC1C66", "1C49A5A52AF386F3362CF933CD5558"},
			{"FFFFFFFE00000000FFFFFFFFFFFFFFFE000000020000000000000001FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE000000000000000000000001", "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", "0"}
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str1, 16);
		mp_read_radix(b, tmp_array[i].str2, 16);
		mp_read_radix(c, tmp_array[i].res, 16);
		mp_mod(a, b, a);
		if (mp_cmp(a, c) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, c, NULL);
	return err;
}

static int ltc_test_mod_d(void) {
	void *a;
	unsigned long d;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str1;
		unsigned long mod;
		unsigned long res;
	} tmp_array[20] = {
			{"E70306F29076E8BF7DA5D5563A0A1D", 663883874u, 87677119u},
			{"6A46A66C7F1A4E3BB3BB4B095B8082", 1040178009u, 340478028u},
			{"6880B04992C05D4803723C4A9D7788", 1690151894u, 1187732480u},
			{"265EF60B4DA40923759136BA0C0A5C", 118169354u, 31955840u},
			{"2499F1A77C3060987590610110BA0B", 2094746492u, 1078203347u},
			{"7428BC9B7B0865CF40D743D7EB2793", 2119169066u, 1933899525u},
			{"F577255475039C7594A0FD0BE3927E", 1222289707u, 105246748u},
			{"FF7B580C083B113A69C9D26AC1E7E4", 1493262936u, 683840524u},
			{"94F5905E5633CFF8479EF79D9ECDAF", 797247411u, 281286396u},
			{"5CC06683179E36144B7D921BBECDC5", 254694800u, 200091877u},
			{"E0442BF22B9707383CB5E068A05889", 2808061577u, 2553303241u},
			{"D9EB83C4FBD72087B9F63B5753AB9B", 389295616u, 248005019u},
			{"81F62BDE841DACF9065A29B443580E", 1399115832u, 328396942u},
			{"0AC8AE90729E2DEA9AFD0B25CAF798", 342230715u, 52231220u},
			{"F4BF89BDEEBD4B152B35789D85FE33", 3307757544u, 88541947u},
			{"3F15910B335BECBC56CD52D0F986C6", 2936401451u, 23755171u},
			{"6CA18D6C9F95E3054265D0E8BA8587", 3864796788u, 1506173443u},
			{"23B47607BA0D51761BE7E2F2CFC926", 508117654u, 298269886u},
			{"498F7C009D3064C661BF86CE0955C9", 3699908195u, 2374757021u},
			{"2AF9BF9678BBCB99433FD0BB8F0C81", 1445986198u, 696086091u}
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str1, 16);
		mp_mod_d(a, tmp_array[i].mod, &d);
		if (d != tmp_array[i].res) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, NULL);
	return err;
}

static int ltc_test_gcd(void) {
	void *a, *b, *c;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, &c, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str1;
		const char *str2;
		const char *res;
	} tmp_array[20] = {
			{"11F5483B652452A8A306725B31D574", "3CB337210966A28859D4D7668D1DB9", "0C0AC39A0E8A2D5D"},
			{"2FDA749ECFAE13EE77B65CF600B008", "D6157DCFA1A280D1E9DA882F4B59D6", "1C169C50372107A6"},
			{"D59F612E1673F129DABF3ADBE896FE", "649AFED05BC4AD19716EC1EAEDC354", "5176DDE8DFD32C9A"},
			{"F4C3A58951DB03EADA52A1679F6F57", "2C732AD849958FFA963A8AC59D436C", "0FA412099384779D"},
			{"41E39AE0BC9702DAB374E3697C397A", "3EAD05F4D6D49444ED7FD3B877F467", "0EBA03F8BD2988BD"},
			{"224080C9D379E24F16A980C2164FB3", "5385E7D6F8EEF03F401450712ECDB7", "0C157E845FA4590D"},
			{"29ED30583FF9837A7BE7AB08B5F7B8", "828B49CB4A5314D11B724E859C953F", "0C5935720D05B2FF"},
			{"3235EB3DDC2DB08C464324C349E6AD", "4D11758748D9DBFB891C287CA13181", "0F21750CCC805F05"},
			{"4A4A1561D374585ECD29469B357C38", "BE776E11BB39CDC7AC8F60D762B1EC", "37073B0BE2CEF64C"},
			{"0790EB6AD07EDE318A7B0C0D327D54", "2D6FCB9F049D632DE35DD3F4FAACDD", "03B4A3C3C5FB46C5"},
			{"76262ECA8DC1058B93128D3E31251A", "6FDA8A9A41E502437C08C733A873D9", "D5F334CF945DEFA1"},
			{"7CBDEC5E9B145212E1CA7CE4792C42", "BBF4BCDF101B5129FE6CD442BB9395", "0BD258E676A3199F"},
			{"049100DA58844EB8FA8A41D082631A", "4E90829D6943CD2172066C3D364995", "05E88B7FB6A7C5CF"},
			{"52DF4891C2283FC5BF2B4C0B69D358", "263F188D4A79889BE03190142DF9F0", "60DAE27B72308978"},
			{"EBFC17B632BBC485B5F839BD64C3BB", "61A3B6B4DE64E00D45D458314CB79A", "0F0F5460F85EA879"},
			{"A965D7FECA7146AD777271BF5D7EF7", "87EEA99A5505C7A541F494FE012E53", "0C3608F13E901B2D"},
			{"0326BA75C1F752316F5F5274292776", "2C3E6321ADF0588A0DAFD67A93E672", "164E3A8CEA96FDB6"},
			{"3F1F03F841FD3D35CAB0FF72FC9268", "22A1136BB8FF4715124B08D56632CF", "068BE7EA8405E06B"},
			{"3B128D8EB80D83C9069B6056F1D46A", "99A43D4BEF9746FB1DFCA5CA570539", "0CE4CCE91767A583"},
			{"4A6ED7AB97AD26BDB30F9F1D08BFC0", "6CEDDF1665E68085202CF0962D2C87", "06D2E12B4C97A591"}
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str1, 16);
		mp_read_radix(b, tmp_array[i].str2, 16);
		mp_read_radix(c, tmp_array[i].res, 16);
		mp_gcd(a, b, a);
		if (mp_cmp(a, c) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, c, NULL);
	return err;
}



static int ltc_test_lcm(void) {
	void *a, *b, *c;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, &c, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str1;
		const char *str2;
		const char *res;
	} tmp_array[20] = {
			{"1CD72AF305E2B70B00A3ACC487D9E3", "0359CF141D454BE8D43B26E5E28D09", "333140193D1D3CA50FC3437181DC93C819E8C1FF6CDB"},
			{"20887D09DAE2482ABF2DDF8557EE68", "02291E5C5FB7F049121C767A3042DE", "090C4ADDD0F01706BA3FDF56D2E4A8CDDD91974B3DF8"},
			{"5004706CBCCBC35B3CC02FBEE7B5E8", "6E1BEBD80399E1EBAD06DB5350D78C", "013654C312FA4178D29751DA90F4CE08FE25BA01BABDA8"},
			{"3AE87128D427392FDBB0A2B86AD300", "31FA43363495372DD0C48484BF9BEF", "01AD532023D117D433333D014967831FC061E32D240500"},
			{"8153AE5DD4E379AA4DD37EFA505553", "23D7ABA99A3A9C6F197F23978232EA", "8BE86E2427DF44EFD8DD45BA2C7C9A38B2470E973F5E"},
			{"0118C498DD065C7BE2801406BE9075", "33D8B113CC4FB5536E2EE4716407CA", "10D516AD81CBFCAB7D271D728CD1A123501BB0E7C6A6"},
			{"F54031D703DE3156782F557E5E7E6E", "9EA70E82ED8400C6090FA0CF454BC5", "09A0E3224A84EDB97617B54564D1001A380826E80887EE"},
			{"971F2238A502352FD6558ADB431A84", "50694BA15F239E86FEB1759F80C59E", "01A3D493E860192A9D4454469F68A36184CA594BD1B994"},
			{"1B8E61E370147AAC13D997D8B478C7", "75E9658754C26DAF691DB80E6484EE", "FD742F2BA3A9B5B2823BFD97B31E25137B83300D35EA"},
			{"1ABDBABC32A242F3BA84B5A1427431", "6EFAC7D0B0E88E0491E03E76C16A04", "2F66829F1339D655BBF20479AAD71AB8B280460DDBF4"},
			{"7C83B2627482858392C7FAD745E533", "6B69E54AE451B98064C19C305F3BCE", "037B8CA6839CFFBD34553ED766BEC120D9116B6150CC0E"},
			{"2E93D947F7EE09F099B3A9893E188A", "16FDCE15FFCCB7512980523D50B51D", "484EE59D88F34358780EECD5AB215B71B97E6504D8FA"},
			{"8983974C92490905D31EB1B2ED03D6", "17181A6C1006C2FAE360896B36FB9C", "ABA87CBC76379CD1BAB231404FF96BDCD903C5A4E1E4"},
			{"7C33272C02C76ABC1D3F346D073213", "25A45D48ED4ECAAFAFE15BA47BAE94", "01AABE733614964EA73F10907E228F584EAA63792904A4"},
			{"45D743504F0A5EF102E6F090AB710E", "056965DDE688BA88AABD02A1F901DC", "22AF9102AB7B8DD0AD3C9B28BBB93C06AB84D1521E7C"},
			{"9BB4DB41459C36C50748161723A7", "0660FCD73D0FC7FC4659DD6BD95C4E", "042D8570AC4007821C30DD4789453195F4EA6A9CD602"},
			{"2597F43F9FF991DE5E5C5BA8856ABC", "2C951665B0037C467E979D4F66CF38", "95B859FAED60907ACEB536F81D5499813EB5010FDA18"},
			{"2F811D2706123DB4538AA2AF1201F6", "15990BBD39FFD3D93A062974885AFE", "201C636CDB49FAFF9CC03983E8C7EF8E4FD4F0E1A12E"},
			{"2DC31E80DB414E320B41F01D08FBFF", "593E0F221C10B050AA81B80B76E6B1", "0123FFECE52D5FF2ACDFF86F5B7248C407C9B76A56A76D"},
			{"52E8F61C335E2AD31AC5B8831A0F87", "5885901117733ED51066035F68E350", "046AA167C4583495651796DB381FFA9C5AE21A141077D0"}
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str1, 16);
		mp_read_radix(b, tmp_array[i].str2, 16);
		mp_read_radix(c, tmp_array[i].res, 16);
		mp_lcm(a, b, a);
		if (mp_cmp(a, c) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, c, NULL);
	return err;
}

static int ltc_test_mulmod(void) {
	void *a, *b, *c, *d;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, &c, &d, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str1;
		const char *str2;
		const char *str3;
		const char *res;
	} tmp_array[20] = {
			{"946039AC252CE6B23EA61D7BDA0513", "F8BEF7B2A66D0AFD25EEE5F00ED529", "E254169E1695F0FED5811EFECABE82", "D4B8DF1ACEDBC1238256803ECD5ED3"},
			{"EEDD17AABBF5C3C17FADE95E5E0F52", "FB0CE109B8434EDEEAEE39B180EA05", "83FA6FDAF01601187C02F8F9C9D531", "640DFAB8F9BA7C7045D8539E7DA167"},
			{"E1B7FF24B60CC3D6FAE0DF379E9C52", "77D1E3163B43C4A5F040DBB1D92C45", "C1C6BCCABE7779737DE6D5A0685714", "1E438B961131F3310502F23165D04A"},
			{"3BBCF51B5C023A4725E8C059D02761", "AC8E34AF71A315943A9AD2B6F3FD57", "5E07C58DE785277EF860CE77DA9D47", "4748B9B2DBAAAF9203D4311C994861"},
			{"8471505E1C6DC59719709438B78910", "C90CB967EF2ED10DAC592F321FD094", "8728CA6C946BE4C2F0B2D469CD8E5A", "04B19084EBE1CF71EDFE842AE184A8"},
			{"C8CAACDDB857D74E87ED947CE0D520", "B598BD0B4CB89FA1A78D9AABBB3142", "3C1489FBFFEE75675998EC8367273C", "230E44C7C341924368EBDB4B44725C"},
			{"8A529F853EE0EF4AD72E7C53ADEEF5", "D8757DF26B133B5DFE8B65491F1915", "91269FC8BD5376D3EC6413B837D497", "0B94F8663C6F65A9E509A745ACFF9F"},
			{"D45220BF290FC15F357DC88585FF53", "5F3B076B55BDA581204AADDB6E0469", "B9E7CE59CD52A91CF28A623F3DCDAB", "41937C9FCA6796391A9F3C688D14AB"},
			{"B4434CA8957DB9F492B832A214EF33", "24F4B1B1A25FC615FC40AF4E5C5D03", "FD098128C3B9D8185D7B92E0136C4E", "C196867A9771A200A7ED11025FA15D"},
			{"AE88934074A1D3B716D2EBC3FF74EF", "49CFE44A710E7D35AB3B0E71ED24DF", "7C0F7B56174097BD04C4AC23008375", "271F0E78BA2B2E961FCA04EC3AF721"},
			{"69D71BBE4065FEBF636621A9B398CB", "8F596874A63DB197E13BB8F555E569", "AD480269C59532A1B1D3A48A3EBFC9", "656BD1F3AF1DA4C55520A5022224D1"},
			{"3A77B2392D4B0120D2A6250101BEAA", "D3C522A5AAFDD2F79592A9C537CA7F", "83E0B72265E355898999C714805299", "4A826EF68977973F68090CF9C68856"},
			{"91E133017979FB86622DD953206DC7", "A64DEE9923D431F26563F2DE78B47D", "C2D38A16E83BEA9AA7AECC5C0572DB", "8D76C9F34C0DFCEF5433C0218FE1CE"},
			{"4FF8E538D25C3CD9C9CA4200D19B69", "D78D46FF5B12303785553AB9DEDCB3", "7FBC84F3B7B5F807776BE47B104167", "53B0EE1DB6B4D704765F664986732E"},
			{"129A01B2A4AA9A70E375FCA58C4C74", "23ABA7C3596A5EA96EE67FC3EBA3FC", "5FDD92D40D269CEAE833B385E1D18B", "04BA68A7667F166590E211F5457F0A"},
			{"16A6511BE51692635F3FA980DF155D", "D21D6BFE9281A37539D038727C3577", "6B70A440DCFF5666A97F06428944B5", "5C3F3482063C6A1D0EC2FDB00F53E7"},
			{"D349D30A8F33D5A62186C2998F56AF", "6D206CAC47F35A9918C5DE439D1A49", "9B06949ADF82822974336E48B7175D", "05462A81745552FFDA8C84C291C4CD"},
			{"AFCCC6F3D6BD83529100936DBBADBD", "671F2D69BC1A3DB2B5886B5ABF18D4", "201CE68B11CCD8EE12FBD2FA21686D", "1BD1340C0F7AA88652EB8C79C013A5"},
			{"13433B00C80F35A6171449ED43BA6C", "ECCED64E95AB40E08EBC0C40902DDA", "44ABEA5DFDAB6976615D434D7A740F", "049924CCD71A95EF1CA4DD66B1F151"},
			{"9B6CE45B82C93028AFF23E138622F8", "E376A96E5E0A9D96E8E24D43AB8CD3", "C8C48EF95F50CC70792B7645C150D8", "82F9DE3216076D3989457D8551B658"}
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str1, 16);
		mp_read_radix(b, tmp_array[i].str2, 16);
		mp_read_radix(c, tmp_array[i].str3, 16);
		mp_read_radix(d, tmp_array[i].res, 16);
		mp_mulmod(a, b, c, a);
		if (mp_cmp(a, d) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, c, d, NULL);
	return err;
}

static int ltc_test_sqrmod(void) {
	void *a, *b, *c;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, &c, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str1;
		const char *str2;
		const char *res;
	} tmp_array[20] = {
			{"5532CFBC0320EA53C345353A1EDE29", "3D9CDF2D3622716EF6BA73F8FF27C1", "291A850FEB581243F5D3BA3900A119"},
			{"7DC29F767734EF15E00067D879DBC2", "4A698AC26BD128913FE9C6C4179BCF", "48817620F4BAFC6025F14CFFE358ED"},
			{"4B7BF850D3E0AE720BC1C59EF29B49", "B34A6976978EA7DE753705C9DBC1EC", "11DEE38F5CFC0AC677E6178E17CABD"},
			{"0E8C164B36087852D0B3CC75BC538B", "AD01C1992E3E850AE310D62024211A", "11DF3A0359B62C8CAE61C735B591D1"},
			{"4D18285877BA3C04404E681A8F2AC7", "364339D2DB8421BE2DE47147B5B5B7", "1067FABCCBC6A8C9D666F83627C46A"},
			{"49B5D8E38DF8677EA8F9AB22D6FE24", "13E9794E15CD6227D358E03ED9FAFB", "0D2965FCB81DC95B2F831B6C337DFF"},
			{"45179D76CA7A9DB5166217EA8F2488", "4213ED48DEB0C159941B1783667245", "1A6197368A2BDD937B273DEE97A2E9"},
			{"870E665CC5ECF5C541381DB8C802BB", "66024D457FE40CD9E143A4515309F5", "45FD0428195F668F1DF33FCD1C894E"},
			{"FC280BC1A93CF9134B99821544C1BA", "04F1BA5C7D9DDF048E24F915B1EE15", "01BF9ED87AC161105EB74E5188BCC1"},
			{"C338130C2F8F676C8E26424D554299", "1D026135FC11D0E82BEC3928F473DA", "0F8E9CC66C06FB2DFF0ABD01F38F2B"},
			{"2EA5631FEC465AB04A925606BA7A53", "2A7CE8B95CBAC35AEAFFA5568248B5", "29BB61D34988A990A7F592981DEED5"},
			{"6353D50C37CF6570B6852000F153B0", "C930467A2160A057CB4D1712A5D7BF", "8F566DE34979A8DDD301D611A0E58E"},
			{"B795FBB6A60B3401F5812E23A80A25", "AAF33083E55E798403DF5866CF091E", "2F3F4C4832FF2A5D851DDBC337E3E5"},
			{"7B636AAE6615F0DD69B5BA363D1D1E", "46DDC0F6583C55395F8070E4DCB8D8", "0AF5CED3D58F6AE3BB29F621B9A8B4"},
			{"B8B217DD2A9B75081BA6C0B4714D33", "5F6533D6994BF6F021B5C735E62DAC", "159B90588F6F2D4DD8DC963166DA85"},
			{"B0C671CDBDCBCC3C4E85E4698E3C79", "8B1815606BE2D5344C9A5DBC55B6C6", "785808F197D23511AE67914CBDCD6F"},
			{"84C7BF642D9838C61C2C1F7121BE93", "F6CF617F95D7FBB51D3FDA022FD265", "B2F22ECB48CE37C1D5C52983709EDF"},
			{"CEE5ACB1876CAAF1C2B4049AF12800", "2CFB1AD02BC98AC310DF9FE88F7C90", "0E85F1E5EA47DF1DBA7E63D9EF3240"},
			{"6412AE04EEB6DFB5BCFDB8BF6E3BF3", "4ABBE3876415E883BF72F873C4EF49", "151594DF35400D47D9653A368B27CF"},
			{"03488696E1084D231173B1CB98B35A", "7DFCF0FBF5941E476589D37361F2E6", "0827C0F811D0A323007B45306F8848"}
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str1, 16);
		mp_read_radix(b, tmp_array[i].str2, 16);
		mp_read_radix(c, tmp_array[i].res, 16);
		mp_sqrmod(a, b, a);
		if (mp_cmp(a, c) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, c, NULL);
	return err;
}

static int ltc_test_invmod(void) {
	void *a, *b, *c;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, &c, NULL)) != CRYPT_OK) {
		return err;
	}

	// will test values that are invertible !
	static struct {
		const char *str1;
		const char *str2;
		const char *res;
	} tmp_array[20] = {
			{"ACA47FF7B90428122D04A806F0C362", "8C1F5EABD66622D198ADAE2D46D53D", "493C6788F4DEBAF2A672E2818B8209"},
			{"9B837F3F57C0D06B6672F6F38DE92D", "B19B9C4CE8DDA7408D1A1DC8104B97", "86360789D7714A0E33DCF6AAB1819C"},
			{"077514FB4FF055F52C89D8EDE0FAC8", "99C0C3AF67C57882B4AB8B1E4F46A7", "8848D3241ACA2CC1470BCF00425E73"},
			{"DAF413A4A43CE5F00A917F5D2922A2", "F60FD31EE99D8493F8653EE163E521", "16872AF77E4E6055DC81C2B632BA78"},
			{"8E527FFA1DAE86D982499FDEB0FAB1", "FA93B603243150282293100433FB8F", "79558C76ED0A78C030780A13151081"},
			{"673535255FBECCA0DE03FE91716154", "1C8A0CAB7CB93F772FBD20D54CEBCD", "1A1347ED9E552072687665FBC8EB38"},
			{"4DA878A37F383C2340C33CF56B98D0", "23D4AB0F97BC607C57E15D3F4B9BD9", "1938E4B5BC4D070FA34F7D166DB121"},
			{"9176AA936C7792C8C82BB0CAB6D98E", "ED352A694240A6F0C7F218C6148F1B", "97765BB1CC6AC815F9D8486A6849F5"},
			{"3BB05C35303BBA518B0F432F173AE3", "DA2D3B6C1ADBA3D1183048A685020F", "83A24AD3BAB0AB3BE8B1BA68E944B5"},
			{"DD49482E74135DF4D093606054C801", "601122A19C853CE436DCE376C63B5F", "31F71306CEBE4BC6854C40A26A9773"},
			{"788BDBEE8E041C5F0A87E37D954357", "56CAD67DBBFDDBB6F8033AAC46C8FF", "20E0DE5C06AB37ED9D44599BC80DD8"},
			{"25F1D64019121F9D3FDC1882E7E210", "CBEEF1B3AA827D514E25927EF4AD65", "5C87C029F51BFE65549503170BDD72"},
			{"96A843777936EBEE4593F40E8ABEEF", "534D93681B08EA0EF1ED404C983EFF", "28AFC16042C761C505708D899CF9F2"},
			{"ECFC202D1E1A5D82EAF83F72CE0A2B", "9685ABBC9B5FE3849CE29E6C6A98A9", "0D396DF965F7DFF78B2D4A2A2370E8"},
			{"8BB41426A845235758C582DF740A12", "D26A1F480A50C22FA57E031C2AAF45", "37C45A260BCFC57DFBC4FA3323DF3A"},
			{"C5D860BEA3B9E1354F17D24FFE56A6", "EA9106469622B6F1DB31A4160098B3", "9678B7B0BB00F4E6A4F98D56DC2D36"},
			{"95150D8B4288B45F29C31A8A816F79", "0A0EB58CEF892962AE571E62EF247F", "5E1C1CB4F0FCFFDC2E1B9B83032D"},
			{"A6EA9323744DD36F8ADCD347288A8C", "3E3AB30D230A1371EEEB256E0F53F7", "12600AC1CA658AAD247C67C7C33D0D"},
			{"B55479E34DDB425FCC4FE0BF0688CF", "BC7BAE226019E0A025FC427C0D2775", "305D8FCF357EBE918732441209C16C"},
			{"277811283AB608B5EF4270CDB86B6A", "1548F5562FF905DCBD615971C12587", "06EB29633C3E2B37B386688486D62A"}
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str1, 16);
		mp_read_radix(b, tmp_array[i].str2, 16);
		mp_read_radix(c, tmp_array[i].res, 16);

		if (mp_invmod(a, b, a) != CRYPT_OK) {
			err = CRYPT_ERROR;
			goto end;
		}
		if (mp_cmp(a, c) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			goto end;
		}
	}

	// will test value that are NOT invertible ! We will check that
	// the function correctly returns != CRYPT_OK
	static struct {
		const char *str1;
		const char *str2;
	} tmp_array2[20] = {
			{"7FF79FF91F5B6847213AD34294447D", "A8C80E7E9969548AA71CE8CCA965D2"},
			{"0713DC8D76F7CF460055724FCAEEBB", "63DC32AFB93BF6F7D5ED74A94F23"},
			{"5EE7AE62E6D2B60309586EF4BF1328", "4E8E13954FFC8799EEDA849074212D"},
			{"161382A7FE8E8E62844F2DE6687E3B", "2B65B4AE3A2515A89226F64C55DD61"},
			{"9A4FFBD1568C82DBDDBF8945D12FAE", "500C43E76E25BE64E56F0F5D876F69"},
			{"26DBBE1A2C855DFBC1C294A5107217", "285DBF89D7621233E24612B133D179"},
			{"2C20C8DFB30B0D147898DB11AFD51F", "221C6FE2D35E154F8193684362BB51"},
			{"63F9FF4D485192908ABE76005F3B13", "4330FA36462058EAF65E9E42FC5C29"},
			{"1F38BD5323ECB5E145C7B8D39400CC", "2A673DFD8008B35616CF385B34BDAE"},
			{"AA83BBCACD54C511593FBA0928E049", "4D6A365796AC4D98DB578F331BBF3A"},
			{"1A5B6FE363FFA100D34293B3E894", "6A08181171B462732E8C937F29B2"},
			{"A9CE6E30F5FAF036C4EFFD41A53FF3", "B42E0D73BF6E993480AAB7A01B2274"},
			{"0756497DB54DE2EBD9E25C11C8AF38", "46E4610FEAAC6EF8EB5843B147DFB8"},
			{"4F6E24F192439D7BA41C85BAFE6D40", "07329F31D6E6B3C27E75C1F33FE1A0"},
			{"4B437F6B1809B71EC8288B3E0501E6", "4A0E56AC39F52A86B68604C8A4A7CF"},
			{"317F3F5CBFF36092B3EE3603E9C831", "6325FFA459A4AA6CD5BDD6A201376E"},
			{"A43A32681E36FD0B95EA48DBBB7567", "327B513E1342D90DA01E7FAEB0D9AF"},
			{"1711CE0859A227D14871F36317A655", "237A3CA84256E53DCAF1DB998A51CF"},
			{"34A1BBB30400345DC7AEEC57C72E54", "09FC8E322D68F9F987BB4A199362D5"},
			{"0ABD39AEB74838140AD9A22A4279C7", "2204D2BE390F923F3329370602B50E"}
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array2[i].str1, 16);
		mp_read_radix(b, tmp_array2[i].str2, 16);
		// the function invmod MUST return != CRYPT_OK
		if (mp_invmod(a, b, a) == CRYPT_OK) {
			err = CRYPT_ERROR;
			goto end;
		}
	}
	end:
	mp_clear_multi(a, b, c, NULL);
	return err;
}

static int ltc_test_exptmod(void) {
	void *a, *b, *c, *d;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, &c, &d, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str1;
		const char *str2;
		const char *str3;
		const char *res;
	} tmp_array[20] = {
			{"A4BAB4CFE0F15C52B4CB6FDCF2FC01", "4E3E246BAD88F1A262452026EC56EB", "DABC8363B0819E86DA02DA91EB00AD", "98AEE445F6B7BABFB8400797665FBF"},
			{"35E719B21FFBD2E5C136F5729BE667", "14F82D0C889D285A5A194318CB3162", "0E038ED782D76A92347FA8AF850313", "060D9CB89407E5B9B8B7E55DB5DD75"},
			{"CAC958BE320C0DEBAB55B093A1867E", "8BC1CB1E43C8A8AB594B495345C988", "AC2C1C32BF39BF8E8B8253EA453523", "0759A5440F798AE4A18CFC1BE7FE86"},
			{"96B5DE43B52F43A3851580E467D941", "F39F65576E544409C8AE540C935015", "583F716BB44BEF32CF36DED0EC85DB", "42ADFBE1F980C4A116F7B812589ACA"},
			{"1C8882DCF340123A61AE3D6B06B028", "1C1417979EDCDE78ECCB7BD367D411", "821FDD6833C7CF4085234FAAB3E31D", "1A6D52682FB32035F999DFC8DA5D56"},
			{"2C7F536A21AE7023756FA40243E8B8", "EC1163D1B3E48DB1BE0E5CE33AEC3A", "0F5F228411E42CBE6A156C4DD65F83", "030693311660176629C0B03FDF23BC"},
			{"E25B642C8DF8B369D7CD603509DAFE", "0ED017666D8E9DF07C4AB613C4B40A", "AFC18FD2A8C952C20A2E029EDB95DF", "6DF660CEFEF2B1929F40B4ABBE9D2C"},
			{"66F4E4177A7F69FD848E86A7C33A71", "9B4B79613E93241592BA64CE2586A7", "85F2BA3B161442B528B15A1449E037", "07CF42B332CA023984E7E49A8BA1BF"},
			{"A8145A149C156822474E39A98B5513", "701EF637F67CAD70634F5141956521", "FE2E0B1A0FE1B2E2606AD32D3EEBDD", "9ABD2609B27E55E13DC0C86C699292"},
			{"5B65A816AC21F84D14B0262FAE16EB", "39A0273AE867374F6B008AA6621033", "137EE3F0774BA7E82ACAE2EA66F1D1", "097DB633871AED8A7364AE983D30B0"},
			{"FF66DA7FAFF640378B718AB9C47FE7", "4F4E718AE34AAC99EFBD769AA9BD41", "6D43F29085C78A1F70111D25F7C1EB", "5285227DBDDDBF6E3967347509A6DA"},
			{"5FB717F6EBDFA8C36ADDF30DEEC361", "814FA371CAC2F23CA08B0B65FF8038", "26D346E9A9452C44F9945954F25ACD", "06E7616CBAC8727153BB8A303514F7"},
			{"67B7B3770292B83F9BE6B641FD52DF", "51E40A7D43D7A295359FC409B5EE86", "0B9C2C5071184D5C8FDF64D88331DB", "0A9FFC90CD0AA23CA41989146CD349"},
			{"7077ED1834A591A6D4D862DCF46DB3", "29BCA4C9AF393620AB61C90C26A2E6", "AE66CAB0CA4D4E3944DE45A969E993", "35127FC8E26099F8D88AA1432FA67F"},
			{"90E4D9A8D5C7FAFFB47860CDED6C29", "E4DB5F0DAD6C2E3E43ED36C368E70E", "FA7CA09EEF3A8D7AE1A62814CAE34D", "23484425E1CB128D40DD4F08515F8C"},
			{"F5F1FCA6DDC99B62C27ACB9BC73FDE", "65C8A9A9DB5DB87325ABA0325B1B46", "714D8D87C8DAA1053CA88849C925A3", "0426F970ECEA0C2A8B09CDC44B8A67"},
			{"B93251B6B3CCAC22EFB0390A8CA327", "57D3AF6BD3FACC20C06CFDE292A217", "A30973D2D17B040594ABD5F7C333B5", "64418E32CCD1602FD5998A7B0B0036"},
			{"E0B189C3608F153E901B2B1D417F2F", "99FC8A18CC12ACFFFFF4D67E5FAA75", "94952082DCB712D930AEF801DC1F73", "4EB73F6C2BC5A2B7295AF48F9ACD4E"},
			{"F0783E2B6EB5AC4585CBA6BC05C451", "6475288C76373CF734B21932FDB3C6", "E1E470ADFB1C3DF4D9C9339BA1CA09", "DABD657BADD65D3387EABB0AF81E03"},
			{"68F51480C777D52876880F02353903", "B6D65D5831FE3A683F4CC8589398C2", "31D1886FFA886AB9BF58F33E0CD085", "0C896B4D0D398F124BC0F7E964E289"}
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str1, 16);
		mp_read_radix(b, tmp_array[i].str2, 16);
		mp_read_radix(c, tmp_array[i].str3, 16);
		mp_exptmod(a, b, c, a);
		mp_read_radix(d, tmp_array[i].res, 16);
		if (mp_cmp(a, d) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, c, d, NULL);
	return err;
}

static int ltc_test_isodd(void) {
	void *a;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str1;
		int is_odd;
	} tmp_array[20] = {
			{"B90C9F9A947FAD908154EF87378930", 0},
			{"03712E58C6B5469D3C96C512D0C546", 0},
			{"7C2E3CE01381E7F420E330922EE290", 0},
			{"6322E1CD41BCE762627674376BF185", 1},
			{"56D15771EF973502595EEB411ED37D", 1},
			{"23C0BFEC124BF994C83CDEF7C9ACD8", 0},
			{"A98C226A9C72F2E3CC10E6D90580A8", 0},
			{"CDDAB6FCB974B209A8E27F11F800C8", 0},
			{"40ADB1A9DE33A1C16791938D494FDC", 0},
			{"41EC98B63EB149CF8A8E72795C8580", 0},
			{"0DF0D72C2C207CF8ACDF7D5BD12DEB", 1},
			{"02B36353A2A846C226F57376599E90", 0},
			{"3E1F14E821C4531AB039DD57D8C5E2", 0},
			{"D10974B495D4A56D3FB6EDC0332935", 1},
			{"69A6C36374BB6AF91654464AE75453", 1},
			{"B8A56F350324D1B26247FCC5AB045C", 0},
			{"DD8E60D8C8811493369D4B5BF0C0BF", 1},
			{"90C0430CABE7A924D3FC8B042E348C", 0},
			{"B51222B32474F63258FC0707C26023", 1},
			{"C4BCF4995A2A5278B0F7199D27EC4A", 0}
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str1, 16);
		if (mp_isodd(a) != tmp_array[i].is_odd) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, NULL);
	return err;
}


static int ltc_test_montgomery_setup(void) {
	void *a, *b, *c;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, &c, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str1;
		const char *r;
		const char* r2;
		mpa_word_t n_inv;
	} tmp_array[20] = {
			{"2814CD485F1227FE4AF246F7754D31", "0324EAC8CF0A92E756A4C18DD4000D", "16912827593513EC5276DFFD0A3130", 1453265967u},
			{"7F4D82B18B3C70283002A3C27ABD29", "665F978670A6CF4F9AB333859033AE", "086AA154E7E99B6C0B0890DC99F6E7", 3235827943u},
			{"3D447BC8073082E66CD5F21D3C654F", "29071DB9FA6D63CB869BFBEACCF51D", "1B4F299449B1C31FC880EC2730228F", 3471076945u},
			{"BF0326D4422166483D8396825C878F", "12C6F99B653FF53594B15756065F67", "4B016C1494DAF269CBDB33949D4F3E", 1905870993u},
			{"89DE6875DC74F41EEF2C1AA2F9121D", "30542D4FF2FF0A9A392A939BDB6431", "4AF53AA44E7639FA209AE886859F44", 1861730251u},
			{"87CC19B987EE8387BA35F4736D3FF3", "51B790AE10EC5A736669BEAC4D987A", "1E3EE8DF35781239DCFC6C76BEA70A", 2700578501u},
			{"BB37211E5F4791635119F598E31401", "0AA0B879BC273A371E8238F98AA6A2", "A6383C6A42007326BB72AE02A6125B", 1599280127u},
			{"FA88AC39727F354D39323228D5F8D7", "92A8696E444EA844AFD2DC5DD94CCD", "8D1F7FFEE8FB4C8142CD51FEDA7C4E", 879068441u},
			{"349FF0A2456ACC1B3F7FFD66F7BA75", "122ABAD4679D5F7C2E8CA23D3A34FF", "1C8097289F864C19907A12B5242F8E", 2985769507u},
			{"96058FA327E584E6E6DE7A16415BF9", "7E875E200D19A6BECD181218AF5BEC", "31FA069CF92C767C92858BF62FF2BA", 860326327u},
			{"FE82D976F19E89C7A900D6C979F657", "7EA3AF976FD7AE8F56285FBC8FB2A9", "E6FC4B83CB17D70280AB4A0E54341F", 3689589401u},
			{"0E64F7C261797D7BB3DC8E6E04E3C9", "0CAA87AAC7C0C069D63B6BB90DB1F8", "06B751E0D5FF372198854E8C3B9B19", 1709398407u},
			{"6779CC0E4AF2025EF58A83A4460C9D", "23D670A8AF982332DC807ECECACFCB", "65DFA3171B0D31BAF467651E106804", 1570186827u},
			{"7D03ACD33208158F379363DE14FE67", "1C7A3FB59773DEDA3E4F956D07452C", "6410B6F7C7864924DC7E0FD98A2505", 1570161321u},
			{"2836C57F3BA7F7023A95031A63CF7B", "1B794561643136D139CB4112E0BE51", "09BC2A0D477443CBF1DD513091AB0A", 3068151885u},
			{"A430477B91151D62FB621E905E9CFB", "18C09668E01732BA32125CFC8954CB", "0F55B8058EF90D4EE55043BFE9692B", 3307008461u},
			{"D8858250E2A90BB671750F5D2CA2AD", "928044949C942EC627E7E0155817EA", "CD4FAA4E3D7BE2E520D4800852E57D", 1080356571u},
			{"8B6B15BD7C4D2826639107B2D21EF7", "0966161DCA58498533BBDDB23B2686", "8086FA9537812147D19C0E7E84321D", 3725327673u},
			{"17178DF37618F51DAA98797F65AF3D", "E05700C752A91EC9AD15AEBB51C2", "0E8F66B4F090AF5CF05050707677DC", 1110106091u},
			{"8942D9FB7C331ED9A4A4ABF50FC4F9", "3E6FD66994BF8478392B98619DFC0B", "875BFAD4E2908559B30B8320CD0229", 2936160951u}
	};

	for (i = 0; i < 20; ++i) {
		void *mont;
		mp_read_radix(a, tmp_array[i].str1, 16);
		mp_montgomery_setup(a, &mont);
		mp_read_radix(b, tmp_array[i].r, 16);
		mp_read_radix(c, tmp_array[i].r2, 16);
		if (mp_cmp(b, ((mpa_fmm_context)mont)->r_ptr) != LTC_MP_EQ ||
				mp_cmp(c, ((mpa_fmm_context)mont)->r2_ptr) != LTC_MP_EQ ||
				((mpa_fmm_context)mont)->n_inv != tmp_array[i].n_inv) {
			mp_montgomery_free(mont);
			err = CRYPT_ERROR;
			break;
		}
		mp_montgomery_free(mont);
	}

	mp_clear_multi(a, b, c, NULL);
	return err;
}

static int ltc_test_montgomery_normalization(void) {
	void *a, *b;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *str1;
		const char *r;
	} tmp_array[20] = {
			{"61FEBFB2314923F624A78E759CA8BD", "4B43CB07652629B85AC8451B37B2D4"},
			{"CE9E61C08BF0E73E33409B04BFE037", "25E0F492B6B1A7FA89000B1E675BE5"},
			{"BC4B562DEB94A2880C879355029CC7", "0996D993C1F30F0EF7B3B87072E17C"},
			{"4DE131E629F57811EEA5FAD8291CC7", "273312E028988D1700BAEFE0F07641"},
			{"F021B7A735F93AC73B4CE395ED49C3", "DC2CDE56A7318C50FE4E30B3E1A0D0"},
			{"4A033428E886ECC4EDC05403E3CE7B", "22ECAE94258F7B36161D8E8D7730C9"},
			{"51FDA55EF9021D470EE80ECA851B11", "1958DC94D2669F3879B9D5EA9085F1"},
			{"086B575AE67C1C67185B3316252149", "27DC0FD24061436AF6A6A703EC58"},
			{"C78A54D0058EB54C086714B786547B", "56C35578E127B6953BED74DBE3C268"},
			{"BA15AA51BDD5119E6883F9A028BC15", "2235CF9AFB07C6304A88C3C7FD6320"},
			{"22A1B070849AE14C13005D6D8DF8F7", "0D04006BF756E9C3914D8252BBFE84"},
			{"B479FD78000825181FF4CB04122353", "170596D7F47366CAAFE4213A47E94F"},
			{"FC1984D172E9709FFED6B1586B2F83", "F22EA018BDD30E212CCA938B8EEE77"},
			{"7CFFC0A55A1D1385C661147124E289", "2481AD8B8C7C0A2DF14A2868804F94"},
			{"D3B5307A4FB5EF0D587824798DBAE9", "764C7C5DC96674E436FBF947ED64C3"},
			{"BCEC3D4E0BE0112A9998B2222B89CB", "A8B52483F328CC6C679F3DD127C3A2"},
			{"0EC3B8E8263DDA1B1E6F58DDD5C95B", "0AF877790BBCEDDE61B16A47CF506E"},
			{"C543579D275C3F6CA41ED550169FCB", "2CAA6030F45DBF1B28035C22A8C4BC"},
			{"B648CEA11E5D23197DA2EC67615CE1", "5FE63C0E6B63C740D0867B0676C079"},
			{"B3E4F977C8E846282F914C101AED13", "366D49AE55BC3EDC5D67D919B6E8FC"},
	};

	for (i = 0; i < 20; ++i) {
		mp_read_radix(a, tmp_array[i].str1, 16);
		mp_montgomery_normalization(b, a);
		mp_read_radix(a, tmp_array[i].r, 16);

		if (mp_cmp(b, a) != LTC_MP_EQ) {
			err = CRYPT_ERROR;
			break;
		}
	}

	mp_clear_multi(a, b, NULL);
	return err;
}

static int ltc_test_montgomery_reduce(void) {
	void *a, *b, *c;
	int i;
	int err = CRYPT_OK;

	if ((err = mp_init_multi(&a, &b, &c, NULL)) != CRYPT_OK) {
		return err;
	}

	static struct {
		const char *p;
		const char *n;
		const char *n_mod_p;
	} tmp_array[20] = {
			{"DDC418ADCAB00456FC187EA0434E0F", "7149BF2EF402AC0F67C6008C5D72AD4BDA375E53AFD22F7FB5B13C037FB0", "BFC3DD062CD27DE20471D724C37A5A"},
			{"09171A1A577037E27A7BA669762809", "25A09EEBF24301AABFD74E6196564371428A30D72103EE399C4033A992", "FC772DA2AD6C11AB43B37F8B641E"},
			{"C96A521CEB2B9433B07E365F431757", "6B7DDC41E753912CD39D1055598C94438495F0AD2127D3B09BCCB9E42960", "623E6EC8B8A9EA9D7AB5D18A93C891"},
			{"7D2E7915089BEE7DABA4F56A0769E3", "3D05411A4512A2D9037077010154ADEF5AB48A74BB9D99DC28717ECC4490", "3975211A24ED994A99D8D861CA4277"},
			{"06F06B83AEA77716ECEE9F0143380F", "0ED78D002FEA886AC234E3A3AD41BC9745047DED61D8CF40F803A9E4D9", "0687184AC0861B76E3ACBE1EAA24A3"},
			{"48C45945075280B2452C8C8F131FA9", "0FA11CA339A9254370A013F73581D9985151B746EB23977745BE4F722CA6", "2E7741F5DD60A0334450B5A116DF7B"},
			{"40ED19EB4828515F73A1BDE88E1373", "05F636AE2AC5AF3C53D2F5B0143BAB284D8D593E8B4AE17CDC7A6E23FF2B", "07898E0915EA776D32BD0CA1ADE0B6"},
			{"79919FC4862E17B8781B206E347227", "39287B3F8D4AC38E302ADB600B4D6592990776D76D06E8B7CBAEA93EAE20", "38305C0F26ED021D1AC3366BF6B444"},
			{"90099DC51C74F74F69E9F757EEE875", "2BB9543F9C634BC8027F91E557C1F62F86101E13784A1E94A1B1E0DFC75C", "7DF0A23F494C64DD8CFAD2A99CD1A8"},
			{"DBC6ED9586088E1DBFE8D1616E5297", "AFF3DA273D793F9A1B78773F952ECD462B41F374688DDFF439B27C1E5F04", "271054D840E344F723FED9BE0CBF03"},
			{"3C2622793D457098CE762D62B597E3", "0D2361BF27A47C1CE1640CC563411A3CE62A57682EAA53150C538C56B477", "1DF5072CFF95BF4966A893E5964070"},
			{"58F98523DF9E583E80CA8B76367A1D", "1CF5DE923A53E95EE2351F70A6098BDA7A1D438AC9914A62AA1205257B17", "303CBDECD6F9E515AF77D52CE0F423"},
			{"DB8FA21A02CD5C4619F15ECDA6313F", "222091493EDF5DD96CFEC9927666B895F4C04A7A98BD7EAE799540C8C388", "6C1F5DE1756F18280266D69C73D4EB"},
			{"5D7B0BF6FDE092B12F98DB6E7D60C5", "115CDD5A83C730029333009AA3D3B42ABB4177BC03B2D7B64266E8235221", "1C70B47027B93459E5DA83DD84A30F"},
			{"D3795DF6CF776199AAD4094B2E7587", "90A986C673E70E548DDBE169444331F3B86FC572E7FA90FEBD26E5723D6B", "C181627DD32F4EC02E9A7A2CA686C5"},
			{"6AD652BBF598782D7CDCDADFEFE36F", "09CCC26707D5F77D44E422980C50E2E91E7FE35201C0EEAA44FB750F6D98", "60DA8339731E6AA0C7A7A9BE0CDBAC"},
			{"14E0E490E8947F78E389779EE9F2A3", "019E570BD730ECE7FBC93E272DB46E7C9A6027476724EDB9E4C8F1A45B8E", "07AE2611396A3048798FEDEC173E3B"},
			{"79D539ABF638E2B74C8D06C6E74BDD", "2E8CFAA9C96F3D00CBE096E350D13100336D52116F080C8D1ED5CBCE3EBE", "33899FCA51FFFDC4A6E8CEDEB29EF6"},
			{"5B7486F361C66753D15A5BB3C2431D", "1F9715DBBD045112E351C6F5C95A9ACC975D8FA6AAA61A9EE9E07A8500BA", "5471BD9791FF2E7C2FCB7AD30846E2"},
			{"CE93293F937127D09D1C1D84C20B4D", "800406CDA0343081FD4C3E48F2519BE933008C4140AECD305B09450B2249", "A3A6F8C2DA772042A65A80D5915EC3"}
	};

	for (i = 0; i < 20; ++i) {
		void *mont;
		mp_read_radix(a, tmp_array[i].p, 16);
		mp_montgomery_setup(a, &mont);
		mp_read_radix(b, tmp_array[i].n, 16);
		mp_read_radix(c, tmp_array[i].n_mod_p, 16);
		mp_montgomery_reduce(b, a, mont);
		if (mp_cmp(b, c) != LTC_MP_EQ ) {
			mp_montgomery_free(mont);
			err = CRYPT_ERROR;
			break;
		}
		mp_montgomery_free(mont);
	}

	mp_clear_multi(a, b, c, NULL);
	return err;
}

static int ltc_test_rsa(void) {

	unsigned char in[1024], out[1024], tmp[1024];
	rsa_key       key;
	int           hash_idx, prng_idx, err, i, j;
	unsigned long inlen, outlen, tmplen;
	void *a, *b;

	hash_idx = find_hash("sha1");
	prng_idx = find_prng("yarrow");
	if (hash_idx == -1 || prng_idx == -1) {
		fprintf(stderr, "rsa_test requires LTC_SHA1 and yarrow");
		return 1;
	}

	if (mp_init_multi(&a, &b, NULL) != CRYPT_OK) {
		return CRYPT_MEM;
	}

	for (j = 0; j < 20; ++j) {
		DO(rsa_make_key(&yarrow_prng, prng_idx, 1024/8, 65537, &key));
		for (inlen = 1; inlen <= 86; ++inlen) {
			/* make a random key/msg */
			yarrow_read(in, inlen, &yarrow_prng);
			//            printf("\n\nin = ");
			//            for (i = 0; i < inlen; ++i) {
			//                printf("%02X", in[i]);
			//            }
			outlen = sizeof(out);
			if ((err = ltc_mp.rsa_me(in, inlen, out, &outlen, PK_PRIVATE, &key)) != CRYPT_OK) {
				rsa_free(&key);
				goto end;
			}
			//            printf("\nout = ");
			//            for (i = 0; i < outlen; ++i) {
			//                printf("%02X", out[i]);
			//            }

			tmplen = sizeof(in);
			if ((err = ltc_mp.rsa_me(out, outlen, tmp, &tmplen, PK_PUBLIC, &key)) != CRYPT_OK) {
				rsa_free(&key);
				goto end;
			}
			//            printf("\ntmp = ");
			//            for (i = 0; i < tmplen; ++i) {
			//                printf("%02X", tmp[i]);
			//            }
			mp_read_unsigned_bin(a, in, inlen);
			mp_read_unsigned_bin(b, tmp, tmplen);
			if (mp_cmp(a, b) != LTC_MP_EQ) {
				rsa_free(&key);
				err = CRYPT_ERROR;
				goto end;
			}

		}
		rsa_free(&key);
	}

	end:
	mp_clear_multi(a, b, NULL);
	return err;
}

static int ltc_test_dsa(void) {

	void *r, *s;
	unsigned char msg[16];
	dsa_key       key;
	int           prng_idx, err, i, j, stat1;
	unsigned long x;

	err = CRYPT_OK;

	prng_idx = find_prng("yarrow");
	if (prng_idx == -1) {
		fprintf(stderr, "dsa_test requires yarrow");
		return CRYPT_ERROR_READPRNG;
	}

	if (mp_init_multi(&s, &r, NULL) != CRYPT_OK) {
		return CRYPT_MEM;
	}

	for (i = 0; i < 10; ++i) {
		/* make a random key */
		DO(dsa_make_key(&yarrow_prng, find_prng("yarrow"), 20, 128, &key));

		/* verify it */
		DO(dsa_verify_key(&key, &stat1));
		if (stat1 == 0) {
			fprintf(stderr, "dsa_verify_key ");
			err = CRYPT_ERROR;
			dsa_free(&key);
			goto end;
		}

		for(j = 0; j < 20; ++j) {
			/* randomize the hash of the message */
			yarrow_read(msg, sizeof(msg), &yarrow_prng);

			/* sign the hash of the message */
			DO(dsa_sign_hash_raw(msg, sizeof(msg), r, s, &yarrow_prng, find_prng("yarrow"), &key));

			DO(dsa_verify_hash_raw(r, s, msg, sizeof(msg), &stat1, &key));
			if (stat1 == 0) {
				fprintf(stderr, "dsa_verify hash ");
				err = CRYPT_ERROR;
				dsa_free(&key);
				goto end;
			}
		}
		dsa_free(&key);
	}

	end:
	mp_clear_multi(r, s, NULL);
	return err;

}

int unit_test(void) {
	DO(ltc_test_neg());
	DO(ltc_test_add_neg());
	DO(ltc_test_copy());
	DO(ltc_test_set_int());
	DO(ltc_test_count_bits());
	DO(ltc_test_cnt_lsb());
	DO(ltc_test_2expt());
	DO(ltc_test_toradix());

	DO(ltc_test_add());
	DO(ltc_test_add_d());

	DO(ltc_test_sub());
	DO(ltc_test_sub_d());

	DO(ltc_test_mul());
	DO(ltc_test_mul_d());

	DO(ltc_test_sqr());
	DO(ltc_test_div());
	DO(ltc_test_div_2());
	DO(ltc_test_mod());
	DO(ltc_test_mod_d());

	DO(ltc_test_gcd());
	DO(ltc_test_lcm());

	DO(ltc_test_mulmod());
	DO(ltc_test_sqrmod());
	DO(ltc_test_invmod());

	DO(ltc_test_exptmod());

	DO(ltc_test_isodd());

	DO(ltc_test_montgomery_setup());
	DO(ltc_test_montgomery_normalization());
	DO(ltc_test_montgomery_reduce());

	DO(ltc_test_rsa());
	DO(ltc_test_dsa());
	return CRYPT_OK;
}
